package org.amphiprion.descentv2assistant.dao.xml;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.amphiprion.descentv2assistant.App;
import org.amphiprion.descentv2assistant.ApplicationConstants;
import org.amphiprion.descentv2assistant.entity.Ability;
import org.amphiprion.descentv2assistant.entity.Monster;
import org.amphiprion.descentv2assistant.entity.MonsterAttack;
import org.amphiprion.descentv2assistant.entity.MonsterCharacteristic;
import org.amphiprion.descentv2assistant.entity.Product;
import org.amphiprion.descentv2assistant.entity.Trait;
import org.amphiprion.descentv2assistant.filter.IdFilter;
import org.amphiprion.descentv2assistant.util.PreferenceUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.os.Environment;
import android.util.Log;

public class MonsterXmlDao extends AbstractXmlDao {
	private static MonsterXmlDao instance;

	public static MonsterXmlDao getInstance() {
		if (instance == null) {
			instance = new MonsterXmlDao();
		}
		return instance;
	}

	public Monster getMonster(String monsterId, int act) {
		List<Monster> monsters = getMonsters(null, monsterId, false);
		if (monsters.get(0).getAct() == act) {
			return monsters.get(0);
		} else {
			return monsters.get(1);
		}
	}

	public List<Monster> getMonsters() {
		return getMonsters(null, null, false);
	}

	public List<Monster> getMonsters(IdFilter traitFilter) {
		return getMonsters(traitFilter, null, false);
	}

	public List<Monster> getMonsters(IdFilter traitFilter, boolean lightView) {
		return getMonsters(traitFilter, null, lightView);
	}

	private List<Monster> getMonsters(IdFilter traitFilter, String monsterId, boolean lightView) {

		List<Monster> result = new ArrayList<Monster>();
		String lng = PreferenceUtil.getLanguage();
		InputStream is = null;
		try {
			File f = new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY + "/monsters.xml");

			if (f.exists()) {
				is = new FileInputStream(f);
			}
			if (is == null) {
				is = App.class.getResourceAsStream("/monsters.xml");
			}

			DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
			builderFactory.setNamespaceAware(true);

			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			Document document = builder.parse(is);

			NodeList list = document.getElementsByTagName("monster");
			for (int i = 0; i < list.getLength(); i++) {
				Element heroNode = (Element) list.item(i);
				String productId = heroNode.getAttributes().getNamedItem("product").getNodeValue();
				String id = heroNode.getAttributes().getNamedItem("id").getNodeValue();

				if (monsterId != null && !monsterId.equals(id)) {
					continue;
				}

				Product product = ProductXmlDao.getInstance().getProduct(productId);
				if (!product.isOwned()) {
					continue;
				}
				// NAME
				Element localizedNode = (Element) heroNode.getElementsByTagName("name").item(0);
				String name = getLocalizedText(localizedNode, lng);

				String[] traitIds = heroNode.getAttributes().getNamedItem("traits").getNodeValue().split(",");

				boolean major = getBooleanAttribute(heroNode, "major", false);

				if (traitFilter != null && "ACT".equals(traitFilter.getFilterType())) {
					if (major && !traitFilter.contains("1") && !traitFilter.contains("3")) {
						continue;
					}
					if (!major && !traitFilter.contains("0") && !traitFilter.contains("2")) {
						continue;
					}
				}

				boolean traitAvailable = false;
				List<Trait> traits = new ArrayList<Trait>();
				for (String traitId : traitIds) {
					if (traitFilter == null || traitFilter.getFilterType() != null || traitFilter.contains(traitId)) {
						traitAvailable = true;
					}
					traits.add(TraitXmlDao.getInstance().getTrait(traitId));
				}

				if (!traitAvailable) {
					continue;
				}

				// ACTS
				NodeList actsList = heroNode.getElementsByTagName("act");
				for (int j = 0; j < actsList.getLength(); j++) {
					Element actNode = (Element) actsList.item(j);
					int act = getIntAttribute(actNode, "value", 1);

					if (traitFilter != null && "ACT".equals(traitFilter.getFilterType())) {
						if (act == 2 && !traitFilter.contains("2") && !traitFilter.contains("3")) {
							continue;
						}
						if (act == 1 && !traitFilter.contains("0") && !traitFilter.contains("1")) {
							continue;
						}
					}

					Monster monster = new Monster(id);
					monster.setName(name);
					monster.setAct(act);
					monster.setMajor(major);
					if (!lightView) {
						fillMonster(monster, actNode);
					}
					monster.setTraits(traits);
					monster.setProduct(product);
					result.add(monster);

				}

			}
			is.close();
			return result;
		} catch (Throwable e) {
			Log.e(ApplicationConstants.PACKAGE, "", e);
			if (is != null) {
				try {
					is.close();
				} catch (Throwable ex) {
				}
			}
			return null;
		}
	}

	private void fillMonster(Monster monster, Element minorMajorNode) {
		List<Ability> abilities = new ArrayList<Ability>();
		NodeList list = minorMajorNode.getElementsByTagName("ability");

		for (int i = 0; i < list.getLength(); i++) {
			Element abilityNode = (Element) list.item(i);
			String id = getAttribute(abilityNode, "id", "");
			String param = getAttribute(abilityNode, "param", "");

			Ability ability = AbilityXmlDao.getInstance().getAbility(id).parseAbility(param);
			ability.setFlash(getBooleanAttribute(abilityNode, "flash", false));
			ability.setAction(getBooleanAttribute(abilityNode, "action", false));

			abilities.add(ability);
		}
		monster.setAbilities(abilities);

		Element cNode = (Element) minorMajorNode.getElementsByTagName("characteristic").item(0);
		MonsterCharacteristic mc = new MonsterCharacteristic();
		mc.setSpeed(getIntAttribute(cNode, "speed", 0));
		mc.setHealth(getIntAttribute(cNode, "health", 0));
		mc.setDefense(getAttribute(cNode, "defense", ""));
		monster.setCharacteristic(mc);

		Element aNode = (Element) minorMajorNode.getElementsByTagName("attack").item(0);
		MonsterAttack ma = new MonsterAttack();
		ma.setMelee(getBooleanAttribute(aNode, "melee", true));
		ma.setDice(getAttribute(aNode, "dice", ""));
		monster.setAttack(ma);

	}

}
